/*打印helloworld*/
/*#include <iostream>
using namespace std;

int main()
{
    cout << "hello World" << endl;

    system("pause");

    return 0;
}*/

/*变量：方便管理内存空间*/
/*#include <iostream>
using namespace std;

int main()
{
    int a = 10;
    cout << "a=" << a << endl;

    system("pause");
    return 0;
}*/

/*常量
1.#define宏常量；通常在文件上方定义
2.const修饰的变量：通常在变量定义前加关键字const*/

/*#include <iostream>
using namespace std;

#define Day 7

int main()
{
    cout << "一周总共有：" << Day << "天" << endl;

    const int month = 12;
    cout << "一年总共有：" << month << "月" << endl;
    system("pause");
    return 0;
}*/

/*标识符命名规则
1.不可以是关键字
2.由字母，数字，下划线构成
3.第一个字符只能是自瞄或下划线
4.区分大小写
eg：int abc=10;  int _abc=20; int _123abc=30;*/

/*整型
1.短整型short（-32768~+32767）2字节
2.整型int（十位数）4字节
3.长整型long（十位数）win4字节，linux4字节（32位），8字节（64位）
4.长长整型long long（19位）8字节*/

/*sizeof关键字：统计数据类型所占内存大小*/

/*#include <iostream>
using namespace std;

int main()
{
    short num1 = 10;
    cout << "short占用内存空间为: " << sizeof(num1) << endl; // short
    int num2 = 10;
    cout << sizeof(num2) << endl;
    long num3 = 10;
    cout << sizof(num3) << endl;
    long long num4 = 10;
    cout << sizof(num4) << endl;
    //short<int<=long<=long long
    system("pause");
    return 0;
}*/

/*实型（浮点型）
1.float 4字节，7位有效数字
2.double 8字节 15~16位有效数字*/

/*#include <iostream>
using namespace std;

int main()
{
    // 默认情况下，输出一个小数，会显示出6位有效数字
    float f1 = 3.14f;//需要加f
    cout << f1 << endl;
    double d1 = 3.14;
    cout << d1 << endl;
    cout << sizeof(f1) << endl;
    cout << sizeof(d1) << endl;
    // 科学计数法
    float f2 = 3e2; //
    cout << f2 << endl;
    float f3 = 3e-2; // 3*0.1^2
    cout << f3 << endl;

    system("pause");
    return 0;
}*/

/*字符型变量*/

/*#include <iostream>
using namespace std;

int main()
{
    char ch = 'a'; // 只能是单引号，只能有一个字符
    cout << ch << endl;
    cout << sizeof(ch) << endl;
    cout << (int)ch << endl; // 字符变量对应的ascii编码

    system("pause");
    return 0;
}*/

/*转义字符
\n 换行
\t 水平制表（跳到下一个TAB位置）
\\ 代表一个反斜线字符"\""*/

/*#include <iostream>
using namespace std;

int main()
{
    cout << "hello world\n";
    cout << "\\" << endl;
    cout << "aaa\thelloworld" << endl;
    cout << "aaaaaaaa\thelloworld" << endl;//咋不行
    cout << "a\thelloworld" << endl;

    system("pause");
    return 0;
}*/

/*字符串型
1.c风格字符串    char 变量名[]="字符串值"
2.c++风格字符串  string 变量名[]="字符串值"*/

/*#include <iostream>
#include <string>

using namespace std;

int main()
{
    char str[] = "hello world";
    cout << str << endl;
    string str2 = "hello world";
    cout << str2 << endl;

    system("pause");
    return 0;
}*/

/*布尔类型bool
只有两个值：
true（本质是1）
false（本质是0）
*/

/*#include <iostream>
using namespace std;

int main()
{
    bool flag = true;
    cout << flag << endl;
    flag = false;
    cout << flag << endl;
    cout << sizeof(bool) << endl; // 1字节

    system("pause");
    return 0;
}*/

/*数据的输入
作用：用于从键盘获取数据
关键字：cin
语法：cin>>数据*/

/*#include <iostream>
#include <string>
using namespace std;

int main()
{
    // 1.整型
    int a = 0;
    cout << "赋值a:" << endl;
    cin >> a;
    cout << "a = " << a << endl;
    // 2.浮点型  float f=3.14;
    // 3.字符型  char ch='a';
    // 4.字符串型 string str ='hello';
    // 5.布尔类型 bool flag=false;//非零即真

    system("pause");
    return 0;
}*/

/*运算符
算术运算符：四则运算
前置++，先让变量 + 1，后让表达式计算
后置++，先让表达式计算，后让变量 + 1

赋值运算符：表达式的值赋给变量
/= *= += -=
eg：a=10 a/=2

比较运算符：表达式的比较，返回一个真值或假值
== != < > <= >=
eg:(a==b)//括号优先

逻辑运算符：根据表达式的值返回真值或假值
！ && ||
eg:(a&&b)
*/

/*#include <iostream>
using namespace std;

int main()
{
    int a1 = 10;
    int b1 = 20;

    cout << a1 + b1 << endl; //+-
    //  /的时候=0

    double d1 = 0.5;
    double d2 = 0.22;
    cout << d1 / d2 << endl;

    system("pause");
    return 0;
}*/

/*#include <iostream>
using namespace std;
int main()
{

    int a1 = 8;
    int a2 = 10;

    cout << a1 % a2 << endl; // 8
    system("pause");
    return 0;
}*/

/*程序流程结构
顺序结构 选择结构 循环结构*/
/*if语句*/

/*#include <iostream>
using namespace std;

int main()
{
    int score = 0;
    cout << "分数：" << endl;
    cin >> score;
    if (score > 600)
    {
        cout << "92" << endl;
        if (score > 700)
        {
            cout << "清华北大" << endl;
        }
        if (score > 650)
        {
            cout << "武汉大学" << endl;
        }
        else
        {
            cout << "武汉理工大学" << endl;
        }
    }
    else if (score > 550)
    {
        cout << "一本" << endl;
    }
    else if (score > 450)
    {
        cout << "二本" << endl;
    }
    else
    {
        cout << "未考上" << endl;
    }

    system("pause");
    return 0;
}*/

/*三目运算符*/

/*#include <iostream>
using namespace std;

int main()
{
    int a, b, c;
    cin >> a, b;
    c = (a > b ? a : b);
    cout << "c=" << c << endl;

    (a < b ? a : b) = 100; // 返回的是变量，可以继续赋值
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

    system("pause");
    return 0;
}*/

/*switch语句*/

/*#include <iostream>
using namespace std;

int main()
{
    int score;
    cin >> score;
    switch (score)
    {
    case 5:
        cout << "经典" << endl;
        break;
    case 4:
        cout << "很好" << endl;
        break;
    case 3:
        cout << "不错" << endl;
        break;
    default:
        cout << "烂" << endl;
    }

    system("pause");
    return 0;
}*/

/*whiel循环*/

/*打印0~9*/
/*#include <iostream>
using namespace std;

int main()
{
    int num = 0;
    while (num < 10)
    {
        cout << num << endl;
        num++;
    }

    system("pause");
    return 0;
}*/

/*例题
猜数字*/

/*#include <iostream>
using namespace std;
// time系统时间头文件包含
#include <ctime>
int main()
{
    // 添加随机数种子 利用当前系统时间生成随机数，防止每次生成随机数一样
    srand((unsigned int)time(NULL));
    // 1.生成随机数
    int num = rand() % 100 + 1; // rand()%100+1 生成 0+1~99+1随机数
    // 2.猜测
    int val = 0;
    while (1)
    {
        cin >> val;
        // 3.判断
        if (val > num)
        {
            cout << "过大" << endl;
        }
        else if (val < num)
        {
            cout << "过小" << endl;
        }
        else
        {
            cout << "对了" << endl;
            break;
        }
    }

    system("pause");
    return 0;
}*/

/*do while循环语句
do{循环语句} while{循环条件}
与while区别：会先执行一次循环语句，再判断循环条件*/

// 打印0~9
/*#include <iostream>
using namespace std;

int main()
{
    int num = 0;
    do
    {
        cout << num << endl;
        num++;
    } while (num < 10);

    system("pause");
    return 0;
}*/

/*例题
水仙花数
指一个3位数，它的额每个位上的数字的3次幂之和等于它本身
求所有3位数的水仙花数*/

/*#include <iostream>
using namespace std;

int main()
{
    int num = 100;
    do
    {
        int a, b, c;
        a = num % 10;
        b = num / 10 % 10;
        c = num / 100 % 10;
        if (a * a * a + b * b * b + c * c * c == num)
        {
            cout << num << endl;
        }
        num++;
    } while (num < 1000);

    system("pause");
    return 0;
}*/

/*for循环语句
for(起始表达式;条件表达式;末尾循环体)
{循环语句；}*/

/*#include <iostream>
using namespace std;

int main()
{
    int i = 0;
    for (;;)
    {
        if (i >= 10)
        {
            break;
        }
        cout << i << endl;
        i++;
    }

    system("pause");
    return 0;
}*/

/*例题
敲桌子
1~100，如果数字个位含有7，或者十位含有7，或者是7的倍数，
打印敲桌子，其余数字直接打印输出*/

/*#include <iostream>
using namespace std;

int main()
{
    for (int i = 1; i <= 100; i++)
    {
        if (i % 7 == 0 || i % 10 == 7 || i / 10 == 7)
        {
            cout << "敲桌子" << endl;
        }
        else
        {
            cout << i << endl;
        }
    }

    system("pause");
    return 0;
}*/

/*#include <iostream>
using namespace std;

int main()
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            cout << "*";
        }
        cout << endl;
    }

    system("pause");
    return 0;
}*/

/*例题
乘法口诀表*/

/*#include <iostream>
using namespace std;

int main()
{
    for (int i = 1; i <= 9; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            cout << j << "*" << i << "=" << j * i << "  ";
        }
        cout << endl;
    }
}*/

/*跳转语句*/
/*break语句：跳出选择结构或者循环结构
使用时机：1 出现在switch条件语句中，来终止case并跳出switch
2 出现在循环语句中，来跳出当前的循环语句中
3 出现在嵌套循环中，跳出最近的内层循环语句*/

/*#include <iostream>
using namespace std;

int main()
{
    int select = 0;
    cin >> select;
    switch (select)
    {
    case 1:
        cout << "普通" << endl;
        break;
    case 2:
        cout << "中等" << endl;
        break;
    case 3:
        cout << "困难" << endl;
        break;
    default:
        break;
    }
    system("pause");
    return 0;
}*/

/*#include <iostream>
using namespace std;

int main()
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            if (j == 5)
            {
                break;
            }
            cout << "*";
        }
        cout << endl;
    }

    system("pause");
    return 0;
}*/

/*continue语句：在循环语句中，跳过本次循环中余下尚未执行的语句，
继续执行下一次循环*/

/*#include <iostream>
using namespace std;

int main()
{
    for (int i = 0; i <= 100; i++)
    {
        if (i % 2 == 0)
        {
            continue;
        }
        cout << i << endl;
    }

    system("pause");
    return 0;
}*/

/*goto语句：可以无条件跳转语句
eg: goto FLAG;
    FLAG:*/

/*数组
定义方式：
1.数据类型 数组名[数组长度]；
2.数据类型 数组名[数组长度]={值1，值2....};
3.数据类型 数组名[]={值1，值2....};*/

/*#include <iostream>
using namespace std;

int main()
{
    int arr2[5] = {10, 20, 30, 40, 50};
    for (int i = 0; i < 5; i++)
    {
        cout << arr2[i] << endl;
    }

    system("pause");
    return 0;
}*/

/*一堆数组名用途：
1.统计整个数组在内存中的长度
2.获取数组在内存中的首地址*/

/*#include <iostream>
using namespace std;

int main()
{
    // 1.统计整个数组在内存中的长度
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    cout << sizeof(arr) << endl;
    cout << sizeof(arr[0]) << endl;
    cout << sizeof(arr) / sizeof(arr[0]) << endl;

    // 2.获取数组在内存中的首地址
    cout << (long long)arr << endl;
    cout << (long long)&arr[0] << endl;
    system("pause");
    return 0;
}*/

/*例题
五只小猪称体重
eg: int arr[5]={300,350,200,400,250};
找出并打印最重的小猪体重*/

/*#include <iostream>
using namespace std;

int main()
{
    int arr[5] = {300, 350, 200, 400, 250};
    int max = 0;
    for (int i = 0; i < 5; i++)
    {
        if (arr[i] > max)
        {
            max = arr[i];
        }
    }
    cout << max << endl;

    system("pause");
    return 0;
}*/

/*例题
数组元素逆置
eg: 1,3,2,5,4
变成4,5,2,3,1*/

/*#include <iostream>
using namespace std;

int main()
{
    int arr[] = {1, 3, 2, 5, 4};
    cout << "逆置前：";
    for (int i = 0; i < 5; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;

    int start = 0;
    int end = sizeof(arr) / sizeof(arr[0]) - 1;

    while (start < end)
    {   //元素互换
        int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
        //下标更新
        start++;
        end--;
    }
    cout << "逆置后：";
    for (int i = 0; i < 5; i++)
    {
        cout << arr[i] << " ";
    }

    system("pause");
    return 0;
}*/

/*冒泡排序
1.比较相邻的元素，如果第一个比第二个打，就交换他们两个
2.对每一对相邻元素做同样的工作，执行完毕后，找到第一个最大值
3.重复以上的步骤，每次比较次数-1，直到不需要比较
eg:4,2,8,0,5,7,1,3,9
排序总轮数=元素个数-1；
每轮对比次数=元素个数-排序轮数-1；*/

/*#include <iostream>
using namespace std;

int main()
{
    int arr[9] = {4, 2, 8, 0, 5, 7, 1, 3, 9};

    cout << "排序前：";
    for (int i = 0; i < 9; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;

    //   总共排序轮数为 元素个数-1
    for (int j = 0; j < 9 - 1; j++)
    {
        // 内层循环对比次数=元素个数-当前轮数-1
        for (int k = 0; k < 9 - j - 1; k++)
        {
            // 如果第一个数比第二个数大，交换
            +if (arr[k] > arr[k + 1])
            {
                int temp = arr[k];
                arr[k] = arr[k + 1];
                arr[k + 1] = temp;
            }
        }
    }

    cout << "排序后：";
    for (int i = 0; i < 9; i++)
    {
        cout << arr[i] << " ";
    }

    system("pause");
    return 0;
}*/

/*二维数组
定义方式：
1.数据类型 数组名[行][列]；
2.数据类型 数组名[行][列]={{数据1，数据2}，{数据3，数据4}}；
3.数据类型 数组名[行][列]={数据1，数据2，数据3，数据4}；
4.数据类型 数组名[][列]={数据1，数据2，数据3，数据4}；
*/

/*#include <iostream>
using namespace std;

int main()
{ // 1.数据类型 数组名[行][列]
    int arr[2][3];
    arr[0][0] = 1;
    arr[0][1] = 2;
    arr[0][2] = 3;
    arr[1][0] = 4;
    arr[1][1] = 5;
    arr[1][2] = 6;
    // 2.数据类型 数组名[行][列] = { {数据1，数据2}，{数据3，数据4} }；
    int arr2[2][3] = {{1, 2, 3}, {4, 5, 6}};
    // 3.数据类型 数组名[行][列] = { 数据1，数据2，数据3，数据4 }；
    int arr3[2][3] = {1, 2, 3, 4, 5, 6};
    // 4.数据类型 数组名[][列] = { 数据1，数据2，数据3，数据4 }；
    int arr4[][3] = {1, 2, 3, 4, 5, 6};
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << arr2[i][j] << " ";
        }
        cout << endl;
    }

    system("pause");
    return 0;
}*/

/*二维数组数组名
1.可以查看占用内存空间大小
2.可以查看二维数组的首地址*/
/*#include <iostream>
using namespace std;

int main()
{
    // 1.可以查看占用内存空间大小
    int arr[2][3] =
        {
            {1, 2, 3},
            {4, 5, 6}};
    cout << "占用内存空间:" << sizeof(arr) << endl;
    cout << "第一行占用内存空间:" << sizeof(arr[0]) << endl;
    cout << "第一个元素占用内存空间:" << sizeof(arr[0][0]) << endl;
    cout << "二维数组行数:" << sizeof(arr) / sizeof(arr[0]) << endl;
    cout << "二维数组列数:" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;
    // 2.可以查看二维数组的首地址
    cout << "二维数组首地址：" << (int)arr << endl;
    cout << "二维数组第一行首地址：" << (int)arr[0] << endl;
    cout << "二维数组第二行首地址：" << (int)arr[0] << endl; // 与第一行相差12
    cout << "二维数组第一个元素首地址：" << (int)&arr[0][0] << endl;
    cout << "二维数组第二个元素首地址：" << (int)&arr[0][1] << endl;

    system("pause");
    return 0;
}*/

/*例题
二维数组应用
考试成绩统计*/

/*#include <iostream>
using namespace std;
#include <string>

int main()
{
    int scores[3][3] =
        {
            {100, 100, 100},
            {90, 50, 100},
            {60, 70, 80}};
    string name[3] = {"张三", "李四", "王五"};
    for (int i = 0; i < 3; i++)
    {
        int sum = 0;
        for (int j = 0; j < 3; j++)
        {
            sum += scores[i][j];
            // cout << scores[i][j] << " ";
        }
        cout << name[i] << "的总分为：" << sum << endl;
    }

    system("pause");
    return 0;
}*/

/*函数
定义：
1.返回值类型
2.函数名
3.参数表列
4.函数体语句
5.return表达式

返回值类型 函数名 {参数列表}
{
    函数体语句

    return表达式
}*/

/*#include <iostream>
using namespace std;

int add(int num1, int num2) // 形参
{
    int sum = num1 + num2;
    return sum;
}

int main()
{ // main函数中调用add函数
    int a = 10;
    int b = 20;

    // 函数调用语法：函数名称(参数)
    // a,b称为实际参数
    // 当调用函数时，实参的值会传递给形参

    int c = add(a, b);

    cout << c << endl;

    system("pause");
    return 0;
}*/

/*值传递：就是函数调用时实参将数值传入给形参
值传递时，如果形参发生改变，并不会影响实参
 */

/*#include <iostream>
using namespace std;

// 定义函数，实现两个数字进行交换函数
// 如果函数不需要返回值，声明的时候可以写void
void swap(int num1, int num2)
{
    cout << "交换前" << endl;
    cout << "num1=" << num1 << endl;
    cout << "num2=" << num2 << endl;

    int temp = num1;
    num1 = num2;
    num2 = temp;

    cout << "交换后" << endl;
    cout << "num1=" << num1 << endl;
    cout << "num2=" << num2 << endl;

    // return;返回值不需要的时候，可以不写return
}
int main()
{
    int a = 10;
    int b = 20;

    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

    // 值传递时，如果形参发生改变，并不会影响实参

    swap(a, b);

    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

    system("pause");
    return 0;
}*/

/*函数的常见形式
 1.无参无返
 2.有参无返
 3.无参有返
 4.有参有返*/

/*#include <iostream>
using namespace std;

// 1.无参无返
void test01()
{
    cout << "this is test01" << endl;
}

// 2.有参无返
void test02(int a)
{
    cout << "this is test02 a=" << a << endl;
}

// 3.无参有返
int test03()
{
    cout << "this is test01" << endl;
    return 1000;
}

// 4.有参有返
int test04(int a)
{
    cout << "this is test04 a=" << a << endl;
    return a;
}

int main()
{
    test01();
    test02(100);
    int num1 = test03();
    cout << "num1=" << num1 << endl;
    int num2 = test04(10000);
    cout << "num2=" << num2 << endl;

    system("pause");
    return 0;
}*/

/*函数的声明：告诉编译器函数名称及如何调用函数，
函数的实际主体可以单独定义
。函数的声明可以多次，但函数的定义只能有一次*/

/*#include <iostream>
using namespace std;
// 函数的声明(如果函数的定义写到main后面则必须要先声明)
// 函数的声明可以多次，但函数的定义只能有一次
int max(int a, int b);
// 函数的定义
int max(int a, int b)
{
    return a > b ? a : b;
}
int main()
{
    int a = 10;
    int b = 20;
    cout << max(a, b) << endl;

    system("pause");
    return 0;
}*/

/*函数的分文件编写
1.创建后缀名为.h的头文件
2.创建后缀名为.cpp的源文件
3.在头文件中写函数的声明
4.在源文件中写函数的定义
eg：#include "swap.h"*/

/*指针
作用：可以通过指针间接访问内存
。内存编号是从0开始记录的，一般用十六进制数字表示
。可以利用指针变量保存地址*/

/*#include <iostream>
using namespace std;

int main()
{
    // 1.定义指针
    int a = 10;
    // 指针定义的语法：数据类型*指针变量
    int *p;
    // 让指针记录变量a的地址
    p = &a;
    cout << "a的地址为:" << &a << endl;
    cout << "指针p为:" << p << endl;

    // 2.使用指针
    // 可以通过解引用的方式来找到指针指向的内存
    // 指针前家*代表解引用，招聘到指针指向的内存
    *p = 1000;
    cout << "a=" << a << endl;
    cout << "*p=" << *p << endl;

    system("pause");
    return 0;
}*/

/*指针所占内存空间
32位 4字节
64位 8字节*/

/*#include <iostream>
using namespace std;

int main()
{
    // 指针所占内存空间
    int a = 10;
    // int *p;
    // p = &a;
    int *p = &a; // p
    cout << "sizeof(int*)=" << sizeof(int *) << endl;

    system("pause");
    return 0;
}*/

/*空指针和野指针
空指针:指针变量指向内存中编号位0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的*/

/*#include <iostream>
using namespace std;

int main()
{
    // 空指针
    // 1.用于给指针变量进行初始化
    int *p = NULL;
    // 2.空指针不可以访问
    // 0~255之间的内存编号是系统占用的，不可以使用
    *p = 100;//error

    //野指针
    //程序中，要避免使用野指针
    int *p=(int*)0x1100;//error
    cout<<*p<<endl;

    system("pause");
    return 0;
}*/

/*const修饰指针
1.const修饰指针——常量指针：指针的指向可以改，指向的值不可以改，常指向改值不改
2.const修饰常量——指针常量：指针的指向不可以改，指向的值可以改，指常值改向不改
3.const即修饰指针，又修饰常量：都不可以改 */

/*#include <iostream>
using namespace std;

int main()
{
    int a = 10;
    int b = 10;
    // 1.const修饰指针:常量指针
    const int *p = &a;
    //*p=20; //error
    p = &b; // yes

    // 2.const修饰常量：指针常量
    int *const p2 = &a;
    *p2 = 100; // yes
    // p2=&b;//error

    // 3.const修饰指针和常量
    const int *constp3 = &a;
    //*p3 = 100;//error
    // p3 = &b;//error

    system("pause");
    return 0;
}*/

/*指针和数组
利用指针访问数组中元素*/

/*#include <iostream>
using namespace std;

int main()
{
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    cout << "第一个元素:" << arr[0] << endl;

    int *p = arr; // arr就是数组首地址
    cout << "利用指针访问第一个元素:" << *p << endl;
    p++; // 让指针向后偏移4个字节
    cout << "利用指针访问第二个元素:" << *p << endl;

    // 利用指针遍历数组
    int *p2 = arr;
    for (int i = 0; i < 10; i++)
    {
        // cout << arr[i] <<" ";//普通遍历
        cout << *p2 << " ";
        p2++;
    }

    system("pause");
    return 0;
}*/

/*指针和函数
作用:利用指针作函数参数，可以修改实参的值
1.值传递:不可以改变实参
2.地址传递:可以修饰实参*/

/*#include <iostream>
using namespace std;

void swap01(int a, int b) // 形参
{
    int temp = a;
    a = b;
    b = temp;
    cout << "swap01 a=" << a << endl; // 20
    cout << "swap01 b=" << b << endl; // 10
}

void swap02(int *p1, int *p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
int main()
{
    // 1.值传递
    // 不可以改变实参
    int a = 10; // 实参
    int b = 20;
    // swap01(a, b);
    // cout << "a=" << a << endl;//10
    // cout << "b=" << b << endl;//20

    // 2.地址传递
    // 如果是地址传递，可以修饰实参
    swap02(&a, &b);
    cout << "a=" << a << endl; // 20
    cout << "b=" << b << endl; // 10

    system("pause");
    return 0;
}*/

/*！指针，数组，函数
例题
封装一个函数，利用冒泡排序，实现对整型数组的升序排序
eg:int arr[10]={4,3,6,9,1,2,10,8,7,5};*/

/*#include <iostream>
using namespace std;

// 冒泡排序函数 参数1 数组首地址 参数2 数组长度
void bubbleSort(int *arr, int len)
{
    for (int i = 0; i < len - 1; i++)
    {
        for (int j = 0; j < len - i - 1; j++)
        {
            // 如果j>j+1的值 交换数字
            if (arr[j] > arr[j + 1])
            {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

// 打印数组
void printArray(int *arr, int len)
{
    for (int i = 0; i < len; i++)
    {
        cout << arr[i] << " ";
    }
}

int main()
{
    // 1.先创建数组
    int arr[10] = {4, 3, 6, 9, 1, 2, 10, 8, 7, 5};

    // 数组长度
    int len = sizeof(arr) / sizeof(arr[0]);
    // 2.创建函数，实现冒泡排序
    bubbleSort(arr, len);

    // 3.打印排序后的数组
    printArray(arr, len);

    system("pause");
    return 0;
}*/

/*结构体
概念:结构体属于用户自定义的数据类型，允许用户存储不同的数据类型
通过“.”访问结构体变量中的属性
语法：struct 结构体名 {结构体成员列表};
struct结构体名 变量名
struct结构体名 变量名={成员1值，成员2值...}
定义结构体时顺便创建变量*/

/*#include <iostream>
#include <string>
using namespace std;

// 1.创建学生数据类型：学生包括(姓名，年龄，分数)
// 自定义数据类型，一些类型集合组成的一个类型
// 语法
struct Student
{
    // 成员列表

    // 姓名
    string name;
    // 年龄
    int age;
    // 分数
    int score;
} s3; // 2.3 在定义结构体的时候顺便创建变量

// 2.通过学生类型创建具体学生

int main()
{
    // 2.1 struct Student s1
    // struct关键字创建变量时可以省略
    struct Student s1;
    // 给s1属性赋值，通过“.”访问结构体变量中的属性
    s1.name = "张三";
    s1.age = 18;
    s1.score = 100;
    cout << "姓名: " << s1.name << "年龄: " << s1.age << "分数: " << s1.score << endl;

    // 2.2 struct Stdudet s2={...}
    struct Student s2 = {"李四", 19, 80};
    cout << "姓名: " << s2.name << "年龄: " << s2.age << "分数: " << s2.score << endl;

    // 2.3 在定义结构体的时候顺便创建变量
    s3.name = "王五";
    s3.age = 20;
    s3.score = 60;
    cout << "姓名: " << s3.name << "年龄: " << s3.age << "分数: " << s3.score << endl;

    return 0;
}*/

/*结构体数组
作用:将自定义的结构体放入到数组中方便维护
语法：
struct 结构体名 数组名[元素个数]={{}，{}，...{}}
*/

/*#include <iostream>
#include <string>
using namespace std;

// 结构体数组
// 1.定义结构体
struct Student
{
    // 姓名
    string name;
    // 年龄
    int age;
    // 分数
    int score;
};

int main()
{
    // 2.创建结构体数组
    struct Student stuArray[8] =
        {
            {"张三", 18, 100},
            {"李四", 28, 99},
            {"王五", 38, 66}};
    // 3.给结构体数组中的元素赋值
    stuArray[2].name = "赵六";
    stuArray[2].age = 80;
    stuArray[2].score = 60;
    // 4.遍历结构体数组
    for (int i = 0; i < 3; i++)
    {
        cout << "姓名: " << stuArray[i].name
             << "年龄: " << stuArray[i].age
             << "分数: " << stuArray[i].score << endl;
    }

    return 0;
}*/

/*结构体指针
作用：通过指针访问结构体中的成员
利用操作符->可以通过结构体指针访问结构体属性*/

/*#include <iostream>
#include <string>
using namespace std;

// 结构体指针
// 定义结构体
struct student
{
    // 姓名
    string name;
    // 年龄
    int age;
    // 分数
    int score;
};

int main()
{
    // 创建学生结构体变量
    struct student s = {"张三", 18, 100};
    // 通过指针指向结构体变量
    struct student *p = &s;
    // 通过指针访问结构体变量中的数据
    // 通过结构体指针访问结构体中的属性，需要利用"->"
    cout << "姓名: " << p->name
         << "年龄: " << p->age
         << "分数: " << p->score << endl;

    return 0;
}*/

/*结构体嵌套结构体
作用：结构体中的成员可以是另一个结构体
eg：每个轮数辅导一个学员，一个老师的结构体中，记录一个学生的结构体*/

/*#include <iostream>
#include <string>
using namespace std;
// 定义学生结构体
struct student
{
    string name;
    int age;
    int score;
};
// 定义老师结构体
struct teacher
{
    int id;
    string name;
    int age;
    struct student stu;
};

int main()
{
    // 创建老师
    teacher t;
    t.id = 10000;
    t.name = "老王";
    t.age = 50;
    t.stu.name = "小王";
    t.stu.age = 20;
    t.stu.score = 60;

    cout << "老师姓名:" << t.name
         << " 老师编号:" << t.id
         << " 老师年龄:" << t.age
         << " 老师辅导的学生:" << t.stu.name
         << " 学生年龄:" << t.stu.age
         << " 学生分数:" << t.stu.score << endl;

    return 0;
}*/

/*结构体做函数参数
作用：将结构体作为参数向函数中传递
传递方式有两种：
值传递
地址传递*/

/*#include <iostream>
#include <string>
using namespace std;

// 定义学生结构体
struct student
{
    string name;
    int age;
    int score;
};

// 打印学生信息的函数
// 1.值传递,形参改变，实参不变
void printstudent1(struct student s)
{
    s.age = 100;
    cout << "子函数中 姓名:"
         << " 年龄:" << s.age
         << " 分数:" << s.score << endl;
}
// 2.地址传递,形参改变，实参也改变
void printstudent2(struct student *p)
{
    p->age = 200;
    cout << "子函数2中 姓名: " << p->name
         << " 年龄: " << p->age
         << " 分数: " << p->score << endl;
}
int main()
{
    // 结构体做函数参数
    // 将学生传入到一个参数中，打印学生身上所有数据
    // 创建结构体变量
    struct student s;
    s.name = "张三";
    s.age = 20;
    s.score = 85;
    cout << "main函数中打印 姓名:" << s.name
         << " 年龄:" << s.age
         << " 分数:" << s.score << endl;
    // printstudent1(s);
    printstudent2(&s);
    return 0;
}*/

/*结构体中const的使用
作用：用const防止误操作*/

/*#include <iostream>
#include <string>
using namespace std;

// const使用场景
struct student
{
    string name;
    int age;
    int score;
};

// 将函数中的形参改为指针，可以减少内存空间，
// 而且不会复制新的副本出来
void printstudent(const student *s) //(student s)
{
    // s.age = 150; // 不会改变
    // cout << "姓名: " << p.name
    //     << "年龄: " << p.age
    //      << "分数: " << p.score << endl;
    //  s->age = 150; // 会改变,而加入const之后，一旦有修改的操作就会报错
    cout << "姓名: " << s->name
         << "年龄: " << s->age
         << "分数: " << s->score << endl;
}

int main()
{
    // 创建结构体变量
    struct student s = {"张三", 15, 70};
    // 通过函数打印结构体变量信息
    // printstudent(s);
    printstudent(&s);
    cout << "main函数中张三的年龄为: " << s.age << endl;

    return 0;
}*/

/*！结构体例题
每名老师带领5个学生，总共3名老师
数据学生和老师的结构体，其中在老师的结构体中，
有老师姓名和一个存放5名学生的数组作为成员，
学生的成员有姓名，考试分数，创建数组存放3名老师，
通过函数给每个老师及所带的学生赋值
最终打印出老师数据以及老师所带的学生数据     */

/*#include <iostream>
#include <string>
#include <ctime>
using namespace std;

// 学生结构体
struct student
{
    string sname;
    int score;
};

// 老师结构体
struct teacher
{
    // 姓名
    string tname;
    // 学生数组
    struct student sArray[5];
};

// 给老师和学生赋值的函数
void allocateSpace(struct teacher tArray[], int len)
{
    string nameSeed = "ABCDE";
    // 给老师开始赋值
    for (int i = 0; i < len; i++)
    {
        tArray[i].tname = "teacher_";
        tArray[i].tname += nameSeed[i];

        // 通过循环给每名老师所带的学生赋值
        for (int j = 0; j < 5; j++)
        {
            tArray[i].sArray[j].sname = "student_";
            tArray[i].sArray[j].sname += nameSeed[j];

            // 随机数
            int random = rand() % 61 + 40; // 0+40~60+40
            tArray[i].sArray[j].score = random;
        }
    }
}

void printInfo(struct teacher tArray[], int len)
{
    string nameSeed = "ABCDE";
    // 给老师开始赋值
    for (int i = 0; i < len; i++)
    {
        cout << "老师姓名: " << tArray[i].tname << endl;

        for (int j = 0; j < 5; j++)
        {
            cout << "\t学生姓名:" << tArray[i].sArray[j].sname
                 << " 考试分数: " << tArray[i].sArray[j].score << endl;
        }
    }
}

int main()
{
    // 随机数种子
    srand((unsigned int)time(NULL));
    // 创建3名老师的数组
    struct teacher tArray[3];

    // 打印函数给3名老师的信息赋值，并给老师带的学生信息赋值
    int len = sizeof(tArray) / sizeof(tArray[0]);
    allocateSpace(tArray, 3);

    // 打印所有老师及所带的学生信息
    printInfo(tArray, len);

    return 0;
}*/

/*！结构体例题
设计一个英雄的结构体，包括成员姓名，年龄，性别
创建结构体数组，数组中存放5名英雄
通过冒泡排序的算法，将数组中的英雄按照年龄进行升序排序，
最终打印排序后的结果，信息如下：
{"刘备",23,"男"}
{"关羽",22,"男"}
{"张飞",20,"男"}
{"赵云",21,"男"}
{"貂蝉",19,"女"}*/

/*#include <iostream>
#include <string>
using namespace std;

// 设计英雄结构体
struct Hero
{
    string name;
    int age;
    string sex;
};

// 冒泡排序
void bubbleSort(struct Hero heroArray[], int len)
{
    for (int i = 0; i < len - 1; i++)
    {
        for (int j = 0; j < len - i - 1; j++)
        {
            if (heroArray[j].age > heroArray[j + 1].age)
            {
                struct Hero temp = heroArray[j];
                heroArray[j] = heroArray[j + 1];
                heroArray[j + 1] = temp;
            }
        }
    }
}

// 打印排序后信息
void printHero(struct Hero heroArray[], int len)
{
    for (int i = 0; i < len; i++)
    {
        cout << "姓名: " << heroArray[i].name
             << " 年龄: " << heroArray[i].age
             << " 性别: " << heroArray[i].sex << endl;
    }
}

int main()
{
    // 1.设计英雄结构体

    // 2.创建数组存放5名英雄
    struct Hero heroArray[5] =
        {
            {"刘备", 23, "男"},
            {"关羽", 22, "男"},
            {"张飞", 20, "男"},
            {"赵云", 21, "男"},
            {"貂蝉", 19, "女"},
        };
    int len = sizeof(heroArray) / sizeof(heroArray[0]);
    cout << "排序前:" << endl;
    for (int i = 0; i < len; i++)
    {
        cout << "姓名: " << heroArray[i].name
             << " 年龄: " << heroArray[i].age
             << " 性别: " << heroArray[i].sex << endl;
    }
    //  3.对数组进行排序，按照年龄进行升序排序
    bubbleSort(heroArray, len);

    // 4.对排序后的结果打印输出
    cout << "排序后:" << endl;
    printHero(heroArray, len);

    return 0;
}*/

/*通讯管理系统
1.系统需求
添加联系人，显示联系人，删除联系人，
查找联系人，修改联系人，清空联系人，退出通讯录*/

/*c++核心编程，面向对象*/

/*1.内存分区模型
c++程序在执行时，将内存大小划分为4个区域
代码区：存放函数体的二进制代码，由操作系统进行管理的
全局区：存放全局变量和静态变量以及常量
栈区：由编译器自动分配释放，存放函数的函数值，局部变量等
堆区：由程序员分配和释放，若程序员不释放，程序结束时由操作系统回收
意义：不同区域存放的数据，赋予不同的生命周期，给我们更大的灵活编程
1.1程序运行前
在程序编译后，生成了exe可执行程序，未执行该程序前分为两个区域
代码区：存放cpu执行的机器指令
        代码区是共享的，共享的目的是对于频繁被执行的程序，只需要在内存中有一份代码即可
        代牧区是只读的，使其只读的原因是防止程序意外地修改了她的指令
全局区：全局变量和静态变量存放在此
        全局区还包含了常量区，字符串常量和其他常量也存放在此
        该区域的数据在程序结束后由操作系统释放        */
/*#include <iostream>
using namespace std;

// 全局变量
int g_a = 10;
int g_b = 10;

// const修饰的全局变量，全局常量
int c_g_a = 10;
int c_g_b = 10;

int main()
{
    // 全局区

    // 全局变量，静态变量，常量

    // 创建普通局部变量
    int a = 10;
    int b = 10;
    cout << "局部变量a的地址为：" << (int)&a << endl;
    cout << "局部变量b的地址为：" << (int)&b << endl;

    cout << "全局变量g_a的地址为：" << (int)&g_a << endl;
    cout << "全局变量g_b的地址为：" << (int)&g_b << endl;

    // 静态变量  在普通变量前面加static，属于静态变量
    static int s_a = 10;
    cout << "静态变量s_a的地址为：" << (int)&s_a << endl;

    // 常量
    // 字符串常量
    cout << "字符串常量的地址为：" << (int)&"hellp world" << endl;

    // const修饰的变量
    // const修饰的全局变量，const修饰的局部变量
    cout << "全局常量c_g_a的地址为：" << (int)&c_g_a << endl;
    cout << "全局常量c_g_b的地址为：" << (int)&c_g_b << endl;

    int c_l_a = 10;
    int c_l_b = 10;
    cout << "局部常量c_g_a的地址为：" << (int)&c_l_a << endl;
    cout << "局部常量c_g_b的地址为：" << (int)&c_l_b << endl;

    return 0;
}*/

/*1.2程序运行后
栈区：由编译器自动分配释放，存放函数的参数值，局部变量等
      注意事项：不要返回局部变量的地址，栈区开辟的数据由编译器自动释放*/

/*#include <iostream>
using namespace std;
// 栈区数据注意事项 不要返回局部变量的地址
// 栈区的数据由编译器管理开辟和释放

int *func(int b) // 不能返回void,形参数据也会放在栈区
{
    b = 100;
    int a = 10; // 局部变量  存放在栈区，栈区的数据在函数执行完后自动释放
    return &a;  // 返回局部变量的地址
}
int main()
{
    // 接受func函数的返回值
    int *p = func(1);
    cout << *p << endl; // 第一次可以打印正确的数字，是因为编译器做了保留
    cout << *p << endl; // 第二次这个数据就不再保留了

    return 0;
}*/

/*堆区：由程序员分配释放，若程序员不释放，程序结束时由操作系统回收
        在c++中主要利用new在堆区开辟内存*/

/*#include <iostream>
using namespace std;

int *func()
{
    // 利用new关键字 可以将数据开辟到堆区
    // 指针本质也是局部变量，放在栈上，指针保存的数据是放在堆区
    int *p = new int(10);
    return p;
}
int main()
{
    // 在堆区开辟数据
    int *p = func();
    cout << *p << endl;
    cout << *p << endl;
    cout << *p << endl;

    return 0;
}*/

/*new操作符
c++中利用new操作符在堆区开辟数据
堆区开辟的数据，由程序员手动开辟，手动释放，释放利用操作符delete
语法：new 数据类型
利用new创建的数据，会返回该数据对应的类型的指针*/

/*#include <iostream>
using namespace std;
// 1.new的基本语法
int *func()
{
    // 在堆区创建整型数据
    // new返回的 是该数据类型的指针
    int *p = new int(10);
    return p;
}
void test01()
{
    int *p = func();
    cout << *p << endl;
    cout << *p << endl;
    cout << *p << endl;
    // 堆区的数据 由程序员管理开辟，程序员管理释放
    // 如果向释放堆区的数据，利用关键字delete
    delete p;
    cout << *p << endl; // 内存以及被释放，再次访问就是非法操作，报错
}

// 2.在堆区利用new开辟数组
void test02()
{
    // 创建10整型数据的数组，在堆区
    int *arr = new int[10]; // 数组有10个元素

    for (int i = 0; i < 10; i++)
    {
        arr[i] = i + 100; // 给10个元素赋值100~109
    }

    for (int i = 0; i < 10; i++)
    {
        cout << arr[i] << endl;
    }
    // 释放堆区数组的时候，要加[]才可以
    delete[] arr;
}
int main()
{
    test01();
    test02();

    return 0;
}*/

/*引用
基本使用
作用：给变量起别名
语法：数据类型 &别名 = 原名*/

/*#include <iostream>
using namespace std;

int main()
{
    // 基本语法
    int a = 10;
    // 创建引用
    int &b = a;

    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

    b = 100;
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

    return 0;
}*/

/*引用注意事项
必须初始化
初始化后不可更改*/

/*#include <iostream>
using namespace std;

int main()
{
    int a = 10;
    // int &b; // error
    int &b = a;

    int c = 20;
    // int &b = c; //error
    b = c; // 赋值操作，不是更改引用

    cout << "a=" << a << endl;
    cout << "b=" << b << endl;
    cout << "c=" << c << endl;//全部是20

    return 0;
}*/

/*引用做函数参数
作用：函数传参时，可以利用引用的结束让形参修饰实参
优点：可以简化指针修改实参*/

/*#include <iostream>
using namespace std;

// 交换函数
// 1.值传递
void mySwap01(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;

    // cout << "swap01a=" << a << endl;
    // cout << "swap01b=" << b << endl;
}

// 2.地址传递
void mySwap02(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 3.引用传递
void mySwap03(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}
int main()
{
    int a = 10;
    int b = 20;
    // mySwap01(a, b); // 值传递，形参不会修饰实参
    // mySwap02(&a, &b);//地址传递，形参可以修饰实参
    mySwap03(a, b); // 引用传递，形参也可以修饰实参
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

    return 0;
}*/

/*引用做函数返回值
作用：引用是可以作为函数的返回值存在的
注意：不要返回局部变量引用
用法：函数调用作为左值*/

/*#include <iostream>
using namespace std;

// 1.不要返回局部变量引用
int &test01()
{
    int a = 10; // 局部变量存放在四区中的栈区
    return a;
}

// 2.函数调用作为左值
int &test02()
{
    static int a = 10; // 静态变量，存放在全局区，全局区上的数据在程序结束后系统释放
    return a;
}

int main()
{
    // int &ref = test01();
    // cout << "ref=" << ref << endl; // 第一次结果正确，是因为编译器做了保留
    // cout << "ref=" << ref << endl; // 第二次结构错误，是因为a的内存已经释放

    int &ref2 = test02();
    cout << "ref2=" << ref2 << endl;
    cout << "ref2=" << ref2 << endl;

    // test02返回的就是a，如果函数的返回值是引用，这个函数调用可以作为左值
    test02() = 1000;
    cout << "ref2=" << ref2 << endl;
    cout << "ref2=" << ref2 << endl;
    return 0;
}*/

/*引用的本质
本质：在c++中内部实现是一个指针常量 */

/*#include <iostream>
using namespace std;

void func(int &ref)
{
    ref = 100; // ref是引用，转换为*ref =100
}

int main()
{
    int a = 10;

    // 自动转换为int * const ref=&a,指针常量是指针指向不可改，也说明为什么引用不可更改
    int &ref = a;
    ref = 20; // 内部发现ref是引用，自动帮我们转换为 *ref=20

    cout << "a:" << a << endl;
    cout << "ref:" << ref << endl;

    func(a);

    return 0;
}*/

/*常量引用
作用：常量引用主要用来修饰形参，防止误操作
在函数形参列表中，可以加const修饰形参，防止形参改变实参*/

/*#include <iostream>
using namespace std;

// 打印数据函数
void showValue(const int &val)
{
     val = 1000;
    cout << "val=" << val << endl;
}

int main()
{
    // 常量引用
    // 使用场景：用来修饰形参，防止误操作

    // int a = 10;

    // int &ref = 10; // 引用必须引一块合法得内存空间,error
    // 加上const后，编译器将代码修改 int temp=10;const int & ref=temp;
    //const int &ref = 10;
    // ref = 20;//加入const后变为只读，不可以修改

    int a = 100;
    showValue(a);

    cout << "a=" << a << endl;

    return 0;
}*/

/*函数提高
函数默认参数
在c++中，函数得形参列表中的形参是可以有默认值的
语法：返回值类型 函数名 (参数=默认值) {}*/

/*#include <iostream>
using namespace std;

// 函数默认参数
// 如果我们自己传入数据，就用自己的数据，如果没有，那么用默认值
// 语法：返回值类型 函数名 (参数=默认值) {}
int func(int a, int b = 20, int c = 30)
{
    return a + b + c;
}

// 注意事项
// 1.如果某个位置已经有了默认参数，那么从这个位置往后，左到右都必须有默认值
// int func(int a, int b = 10, int c, int d) // error
//{
//    return a + b + c + d;
//}
// 2.如果函数声明有默认参数，函数实现就不能有默认参数
// 声明和实现只能有一个有默认参数
int func2(int a = 10, int b = 10); // 声明

int func2(int a, int b) // 实现
{
    return a + b;
}
int main()
{
    cout << func(10, 30) << endl;
    cout << func2(10, 10) << endl;

    return 0;
}*/

/*函数占位参数
c++中函数的形参列表可以有占位参数，调用函数时必须填补该位置
语法：返回值类型 函数名 (数据类型){}*/

/*#include <iostream>
using namespace std;

// 占位参数
// 语法：返回值类型 函数名 (数据类型){}
//目前阶段的占位参数我们还用不到，后面课程中会用到
//占位参数 还可以有默认参数
void func(int a, int=10)//(int a,int )
{
    cout << "this is func" << endl;
}

int main()
{
    func(10); // func(10,10);

    return 0;
}*/

/*函数重载
概述
作用：函数名可以相同，提高复用性
满足条件：同一个作用域下
         函数名称相同
         函数参数类型不同 或者 个数不同 或者 顺序不同
注意：函数的返回值不可以作为函数重载的条件*/

/*#include <iostream>
using namespace std;

// 满足条件
// 1.同一个作用域下
// 2.函数名称相同
// 3.函数参数类型不同，或者个数不同，或者顺序不同
void func()
{
    cout << "func 的调用" << endl;
}

void func(int a)
{
    cout << "func(int a) 的调用!" << endl;
}

void func(double a)
{
    cout << "func(double a) 的调用!" << endl;
}

int   func(int a, double b)
{
    cout << "func(int a,double b) 的调用!" << endl;
}

// 注意：函数的返回值不可以作为函数重载的条件
void func(int a, double b)
{
    cout << "func(int a, double b) 的调用!" << endl;
}

int main()
{
    func();       // 调用1
    func(1);      // 调用2
    func(1.0);    // 调用3
    func(1, 1.0); // 调用4(yes),5(error)

    return 0;
}*/

/*函数重载注意事项
引用作为重载条件
函数重载碰到函数默认参数*/

/*#include <iostream>
using namespace std;

// 1.引用作为重载条件
void func(int &a) // int &a=10;不合法
{
    cout << "func(int &a)调用" << endl;
}

void func(const int &a) // const int &a=10; 合法
{
    cout << "func(const int &a)调用" << endl;
}

// 2.函数重载碰到函数默认参数
void func2(int a, int b = 10)
{
    cout << "func(int a,int b)调用" << endl;
}

void func2(int a)
{
    cout << "func(int a)调用" << endl;
}
int main()
{
    // int a = 10;
    // func(a); // 调用1
    // func(10); //调用2
    func2(10); // 函数重载碰到函数默认参数,出现二义性，报错

    return 0;
}*/

/*类和对象
c++面向对象的三大特性为：封装，继承，多态
c++认为万事万物都皆为对象，对象上又其属性和行为
具有相同性质的对象，可以抽象称为类，人属于人类，车属于车类
封装
封装的意义：将属性和行为作为一个整体，表现生活中的事物
           将属性和行为加以权限控制
意义1.在设计类的时候，属性和行为写在一起，表现事物
语法：class 类名{  访问权限: 属性  /行为}；*/

/*设计一个圆类，求圆的周长*/
/*#include <iostream>
using namespace std;

// 圆周率
const double PI = 3.14;

// 圆求周长的公式：2*PI*半径

// class代表设计一个类，类后面紧跟着的就是类名称
class Circle
{
    // 访问权限
    // 公共权限
public:
    // 属性
    // 半径
    int m_r;

    // 行为
    // 获取圆的周长
    double calculateZC()
    {
        return 2 * PI * m_r;
    }
};

int main()
{
    // 通过圆类 创建具体的圆(对象)
    // 实例化 (通过一个类 创建一个对象的过程)
    Circle cl;
    // 给圆对象 的属性进行赋值
    cl.m_r = 10;

    // 2*PI*10=62.8
    cout << "圆的周长为：" << cl.calculateZC() << endl;

    return 0;
}*/

/*设计一个学生类，属性又姓名和学号，
可以给姓名和学号赋值，可以显示学生的姓名和学号*/

/*#include <iostream>
#include <string>
using namespace std;

class Student
{
public: // 访问权限
        // 类中的属性和行为 我们统一称为 成员
    // 属性 成员属性 成员变量
    // 行为 成员函数 成员方法

    string m_Name; // 属性
    int m_Id;
    void showStudent() // 行为
    {
        cout << "姓名：" << m_Name << " 学号：" << m_Id << endl;
    }
    // 给姓名赋值
    void setName(string name)
    {
        m_Name = name;
    }
    // 给学号赋值
    void setId(int id)
    {
        m_Id = id;
    }
};

int main()
{
    // 创建一个具体学生 实例化
    Student s1;
    // 给s1对象 进行属性赋值操作
    // s1.m_Name = "张三";
    s1.setName("张三");
    // s1.m_Id = 1;
    s1.setId(1);

    Student s2;
    // s2.m_Name = "李四";
    s2.setName("李四");

    s2.m_Id = 2;

    // 显示信息
    s1.showStudent();
    s2.showStudent();

    return 0;
}*/

/*封装意义2：
类在设计时，可以把属性和行为放在不同的权限下，加以控制
访问权限有三种
public 公共权限
protected 保护权限
private 私有权限*/

/*#include <iostream>
using namespace std;

// 访问权限有三种
// public 公共权限    成员 类内可以访问 类外可以访问
// protected 保护权限 成员 类内可以访问 类外不可以访问 儿子可以访问父亲中的保护内容
// private 私有权限   成员 类内可以访问 类外不可以访问 儿子不可以访问父亲中的私有内容

class Person
{
public: // 公共权限
    string m_Name;

protected: // 保护权限
    string m_Car;

private: // 私有权限
    int m_Password;

    // public:
private:
    void func()
    {
        m_Name = "张三";
        m_Car = "拖拉机";
        m_Password = 123456;
    }
};

int main()
{
    Person p1; // 实例化具体对象
    p1.m_Name = "李四";
    p1.m_Car = "奔驰";   // 保护权限内容，类外访问不到
    p1.m_Password = 123; // 私有权限内容，类外访问不到
    func();              // private 访问不了

    return 0;
}*/

/*struct和class区别
唯一区别就是默认的访问权限不同
struct默认权限为公共
class默认权限为私有*/

/*#include <iostream>
using namespace std;

class C1
{
    int m_A; // class默认权限为私有
};

struct C2
{
    int m_B; // struct默认权限为公共
};

int main()
{
    C1 c1;
    c1.m_A = 100; // 类外不可以访问,私有
    C2 c2;
    c2.m_B = 100; // 类外可以访问，公共

    return 0;
}*/

/*将成员属性设置为私有
优点1：将所有成员属性设置为私有，可以自己控制读写权限
优点2：对于写权限，我们可以检测数据的有效性*/

/*#include <iostream>
#include <string>
using namespace std;

// 人类
class Person
{
public:
    // 设置姓名
    void setName(string name)
    {
        m_Name = name;
    }
    // 获取姓名
    string getName()
    {

        return m_Name;
    }
    // 获取年龄
    int getAge()
    {
        return m_Age;
    }
    // 设置年龄
    void setAge(int age)
    {
        if (age < 0 || age > 150)
        {
            cout << "年龄" << age << "输入有误，赋值失败 " << endl;
            return;
        }
        m_Age = age;
    }
    // 设置偶像
    void setIdol(string idol)
    {
        m_Idol = idol;
    }

private:
    string m_Name;  // 可读可写
    int m_Age = 18; // 只读  也可以写(年龄必须在0~150)
    string m_Idol;  // 只写
};

int main()
{
    Person p;
    // 姓名设置
    //  p.m_Name = "张三";
    p.setName("张三");
    // 姓名获取
    cout << "姓名：" << p.getName() << endl;
    // 年龄设置
    p.setAge(160);
    // p.m_Age = 20;
    //  获取年龄
    cout << "年龄：" << p.getAge() << endl;
    // 偶像设置
    p.setIdol("小明"); // 只写
    // cout << "偶像：" << p.getIdol() << endl; // 只写状态 外界访问不到

    return 0;
}*/

/*例子
设计立方体类
求出立方体的面积和体积
分别用全局函数和成员函数判断两个立方体是否相等*/

/*#include <iostream>
using namespace std;

// 立方体类设计
// 1.创建立方体类
// 2.设计属性
// 3.设计获取立方体面积和体积
// 4.分别利用全局函数和成员函数 判断两个立方体是否相等
class Cube
{
public:
    // 设置长
    void setL(int l)
    {
        m_L = l;
    }
    // 获取长
    int getL()
    {
        return m_L;
    }
    // 设置宽
    void setW(int w)
    {
        m_W = w;
    }
    // 获取宽
    int getW()
    {
        return m_W;
    }
    // 设置高
    void setH(int h)
    {
        m_H = h;
    }
    // 获取长
    int getH()
    {
        return m_H;
    }
    // 获取立方体面积
    int calculateS()
    {
        return 2 * m_L * m_W + 2 * m_W * m_H + 2 * m_L * m_L * m_H;
    }
    // 获取立方体体积
    int calculateV()
    {
        return m_L * m_W * m_H;
    }
    // 利用成员函数 判断两个立方体是否相等
    bool isSameByClass(Cube &c)
    {
        if (m_L == c.getL() && m_W == c.getW() && m_H == c.getH())
        {
            return true;
        }
        return false;
    }

private:
    int m_L;
    int m_W;
    int m_H;
};

// 利用全局函数判断 两个立方体是否相等
bool isSame(Cube &c1, Cube &c2)
{
    if (c1.getL() == c2.getL() && c1.getW() == c2.getW() && c1.getH() == c2.getH())
    {
        return true;
    }
    return false;
}

int main()
{
    // 创建立方体对象
    Cube c1;
    c1.setL(10);
    c1.setW(10);
    c1.setH(10);
    cout << "c1的面积为：" << c1.calculateS() << endl;
    cout << "c1的体积为：" << c1.calculateV() << endl;
    // 创建第二个立方体
    Cube c2;
    c2.setL(10);
    c2.setW(10);
    c2.setH(10);
    // 全局函数下判断
    bool ret = isSame(c1, c2);
    if (ret)
    {
        cout << "c1和c2是相等的" << endl;
    }
    else
    {
        cout << "c1和c2是不相等的" << endl;
    }
    // 利用成员函数判断
    ret = c1.isSameByClass(c2);
    if (ret)
    {
        cout << "成员函数判断：c1和c2是相等的" << endl;
    }
    else
    {
        cout << "成员函数判断：c1和c2是不相等的" << endl;
    }

    return 0;
}*/

/*!例题
设计一个圆形类，和一个点类，计算点和圆的关系*/

/*#include <iostream>
#include <string>
using namespace std;

// 设计一个点类
class Point
{
public:
    // 设置x
    void setX(int x)
    {
        m_X = x;
    }
    // 获取x
    int getX()
    {
        return m_X;
    }
    // 设置y
    void setY(int y)
    {
        m_Y = y;
    }
    // 获取y
    int getY()
    {
        return m_Y;
    }

private:
    int m_X;
    int m_Y;
};

// 圆类
class Circle
{
public:
    // 设置半径
    void setR(int r)
    {
        m_R = r;
    }
    // 获取半径
    int getR()
    {
        return m_R;
    }
    // 设置圆心
    void setCenter(Point center)
    {
        m_Center = center;
    }
    // 获取圆心
    Point getCenter()
    {
        return m_Center;
    }

private:
    int m_R; // 半径
    // 在类中可以让另一个类 作为本来中的成员
    Point m_Center; // 圆心
};

// 判断点和圆关系
void isInCircle(Circle &c, Point &p)
{
    // 计算两点之间距离 平方
    int distance =
        (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
        (c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
    // 计算半径的平方
    int rDistance = c.getR() * c.getR();
    // 判断关系
    if (distance == rDistance)
    {
        cout << "点在圆上" << endl;
    }
    else if (distance > rDistance)
    {
        cout << "点在圆外" << endl;
    }
    else
    {
        cout << "点在圆内" << endl;
    }
}

int main()
{
    // 创建一个圆
    Circle c;
    c.setR(10);
    Point center;
    center.setX(10);
    center.setY(0);
    c.setCenter(center);
    // 创建一个点
    Point p;
    p.setX(10);
    p.setY(11);
    // 判断
    isInCircle(c, p);

    return 0;
}*/

/*对象的初始化和清理
c++中每个对象也都会有初始设置以及对象销毁前的清理数据设置

构造函数和析构函数
构造函数：主要作用在创建对象时为对象的成员属性赋值，构造函数由编译器自动调用，无须手动调用
析构函数：主要作用在于对象销毁前系统自动调用，执行一些清理工作

构造函数语法：类名(){}
1.没有返回值也不写void
2.函数名称与类名相同
3.构造函数可以由参数，因此可以发生重载
4.程序在调用对象时候会自动调用构造，无须手动调用，而且只会调用一次

析构函数语法：~类名(){}
1.没有返回值也不写void
2.函数名称与类名相同，在名称前加上符号~
3.析构函数不可以由参数，因此不可以发生重载
4.程序在对象销毁前会自动调用构造，无须手动调用，而且只会调用一次*/

/*#include <iostream>
using namespace std;
// 对象的初始化和清理
// 1.构造函数 进行初始化操作
// 2.析构函数 进行清理的操作
class Person
{
public:
    // 1.1构造函数
    // 没有返回值 不用写void
    // 函数名称与类名相同
    // 构造函数可以由参数，因此可以发生重载
    // 程序在调用对象时候会自动调用构造，无须手动调用，而且只会调用一次
    Person()
    {
        cout << "Person构造函数的调用" << endl;
    }
    // 2.析构函数
    // 没有返回值也不写void
    // 函数名称与类名相同，在名称前加上符号 ~
    // 析构函数不可以由参数，因此不可以发生重载
    // 程序在对象销毁前会自动调用构造，无须手动调用，而且只会调用一次
    ~Person()
    {
        cout << "Person析构函数的调用" << endl;
    }
};
// 构造和析构都是必须由的实现，如果我们自己不提供，编译器会提供一个空实现的构造和析构
void test01()
{
    Person p; // 在栈上的数据，test01执行完毕后，释放这个对象
}

int main()
{
    // test01();
    Person p;

    system("pause"); // 如果没有这个，析构也会打印出来
    return 0;
}*/

/*构造函数的分类及调用
两种分类方式：
按参数分为：有参构造和无参构造
按类型分为：普通构造和拷贝构造
三种调用方式：
括号法  显示法  隐式转换法*/

/*#include <iostream>
using namespace std;

// 分类
// 按参数分为：有参构造和无参构造(默认构造)
// 按类型分为：普通构造和拷贝构造

class Person
{
public:
    // 构造函数
    Person()
    {
        cout << "Person的无参构造函数的调用" << endl;
    }
    Person(int a)
    {
        age = a;
        cout << "Person的有参构造函数的调用" << endl;
    }
    // 拷贝构造函数
    Person(const Person &p)
    {
        // 将传入的人身上的所有属性，拷贝到我身上
        age = p.age;
        cout << "Person的拷贝构造函数的调用" << endl;
    }

    ~Person()
    {
        cout << "Person的析构函数的调用" << endl;
    }
    int age;
};

// 调用
void test01()
{
    // 1.括号法
    // Person p1;     // 默认构造函数调用
    // Person p2(10); // 有参构造函数
    // Person p3(p2); // 拷贝函数

    // 注意事项
    // 调用默认构造函数时候，不要加()
    // 因为下面的这行代码，编译器会认为是一个函数的声明
    // Person p1();
    // void func();

    // cout << "p2的年龄为：" << p2.age << endl;
    // cout << "p3的年龄为：" << p3.age << endl;

    //  2.显示法
    // Person p1;
    // Person p2 = Person(10); // 有参构造
    // Person p3 = Person(p2); // 拷贝构造
    // Person(10);//匿名对象 特点：当前行执行结束后，系统会立即回收掉匿名对象
    // cout << "aaaa" << endl;

    // 注意事项2
    // 不用利用拷贝函数 初始化匿名对象 编译器会认为 Person(p3)==Person p3;对象声明
    // Person(p3);

    // 3.隐式转换法
    // Person p4 = 10; // 相当于 写了 Person p4=Person(10);有参构造
    // Person p5 = p4; // 拷贝构造 相当于 =Person(p4);
}

int main()
{
    test01();

    return 0;
}*/

/*拷贝函数调用时机
通常有三种情况：
1.使用一个已经创建完毕的对象来初始化一个新对象
2.值传递的方式给函数参数传值
3.以值方式返回局部对象*/

/*#include <iostream>
using namespace std;

class Person
{
public:
    Person()
    {
        cout << "Person默认构造函数调用" << endl;
    }

    Person(int age)
    {
        cout << "Person有参构造函数调用" << endl;
        m_Age = age;
    }

    Person(const Person &p)
    {
        cout << "Person拷贝构造函数调用" << endl;
        m_Age = p.m_Age;
    }

    ~Person()
    {
        cout << "Person析构函数调用" << endl;
    }

    int m_Age;
};

// 1.使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
    Person p1(20);
    Person p2(p1);

    cout << "p2的年龄为：" << p2.m_Age << endl;
}

// 2.值传递的方式给函数参数传值
void doWork(Person p)
{
}

void test02()
{
    Person p;
    doWork(p);
}

// 3.以值方式返回局部对象
Person doWork2()
{
    Person p1;
    cout << (int *)&p1 << endl;
    return Person(p1); // 不能return p1;
}
void test03()
{
    Person p = doWork2();
    cout << (int *)&p << endl;
}

int main()
{
    // test01();
    // test02();
    test03();

    system("pause");
    return 0;
}*/

/*构造函数调用规则
默认情况下，c++编译器至少给一个类添加3个函数
1.默认构造函数(无参，函数体为空)
2.默认析构函数(无参，函数体为空)
3.默认拷贝构造函数，对属性进行值拷贝
规则如下：
如果用户定义有参构造函数，c++不再提供默认无参构造，但是会提供默认拷贝构造
如果用户定义拷贝构造函数，c++不会再提供其他构造函数*/

/*#include <iostream>
using namespace std;

// 1.创建一个类，c++编译器至少给一个类添加3个函数
// 默认构造(空实现)
// 析构函数(空实现)
// 拷贝构造(值拷贝)

// 2.如果用户定义有参构造函数，c++ 不再提供默认无参构造，但是会提供默认拷贝构造
// 3.如果用户定义拷贝构造函数，c++ 不会再提供其他构造函数 class Person
{
public:
    // Person()
    // {
    //     cout << "Person的默认构造函数调用" << endl;
    // }
    // Person(int age)
    // {
    //     cout << "Person的无参构造函数调用" << endl;
    //     m_Age = age;
    // }
    // Person(const Person &p)
    // {
    //     cout << "Person的拷贝构造函数调用" << endl;
    //     m_Age = p.m_Age;
    // }

    ~Person()
    {
        cout << "Person的析构函数调用" << endl;
    }
    int m_Age;
};

void test01()
{
    Person p;
    p.m_Age = 18;
    Person p2(p);
    cout << "p2的年龄为：" << p2.m_Age << endl;
}

void test02()
{
    Person p(28);
    Person p2(p);
    cout << "p2的年龄为：" << p2.m_Age << endl;
}
int main()
{
    // test01();

    system("pause");
    return 0;
}*/

/*深拷贝与浅拷贝
浅拷贝：简单的赋值拷贝操作
深拷贝：在堆区重新申请空间，进行拷贝操作
总结：如果属性有在堆区开辟的，一定要自己提供拷贝构造函数，
防止浅拷贝带来的问题*/

/*#include <iostream>
using namespace std;

class Person
{
public:
    Person()
    {
        cout << "Person的默认构造函数调用" << endl;
    }
    Person(int age, int height)
    {

        m_Age = age;
        m_Height = new int(height);
        cout << "Person的有参构造函数调用" << endl;
    }

    // 自己实现拷贝构造函数 解决浅拷贝带来的问题
    Person(const Person &p)
    {
        cout << "Person的拷贝构造函数调用" << endl;
        m_Age = p.m_Age;
        //  m_Height = p.m_Height; 编译器默认实现就是这行代码
        // 深拷贝操作
        m_Height = new int(*p.m_Height);
    }
    ~Person()
    {
        // 析构代码，将堆区开辟数据做释放操作
        if (m_Height != NULL)
        {
            delete m_Height;
            m_Height = NULL;
        }
        cout << "Person的析构函数调用" << endl;
    }
    int m_Age;
    int *m_Height;
};

void test01()
{
    Person p1(18, 160);
    cout << "p1的年龄围为：" << p1.m_Age << "身高为：" << *p1.m_Height << endl;

    Person p2(p1);
    cout << "p2的年龄围为：" << p2.m_Age << "身高为：" << *p2.m_Height << endl;
}

int main()
{
    test01();

    system("pause");
    return 0;
}*/
